//
// Created by Sivin on 2024/5/11.
//

#include "MediaOutput.h"


static void perror(int errorCode) {
  char errbuf[AV_ERROR_MAX_STRING_SIZE];
  av_strerror(errorCode, errbuf, sizeof(errbuf));
  printf("Error: %s\n", errbuf);
}

MediaOutput::MediaOutput(std::string savePath)
    : outFilePath_(std::move(savePath)) {
}

MediaOutput::~MediaOutput() {
  if (fmtCtx != nullptr) {
    avformat_close_input(&fmtCtx);
    avformat_free_context(fmtCtx);
    fmtCtx = nullptr;
  }
}

int MediaOutput::Configure(AVCodecParameters *inputCodecPar) {
  avformat_alloc_output_context2(&fmtCtx, nullptr, nullptr, outFilePath_.c_str());
  if (fmtCtx == nullptr) {
    av_log(nullptr, AV_LOG_ERROR, "Cannot create avi output format\n");
    return -1;
  }
  AVStream *outVideoStream = avformat_new_stream(fmtCtx, nullptr);
  if (outVideoStream == nullptr) {
    printf("Failed allocating output stream.\n");
    return -1;
  }
  outVideoStream->time_base.den = 25;
  outVideoStream->time_base.num = 1;
  if (avcodec_parameters_copy(outVideoStream->codecpar, inputCodecPar) < 0) {
    printf("Cannot copy codec para.\n");
    return -1;
  }
  return 0;
}

int MediaOutput::Open() {
  //打开输出文件
  if (!(fmtCtx->oformat->flags & AVFMT_NOFILE)) {
    if (avio_open(&fmtCtx->pb, outFilePath_.c_str(), AVIO_FLAG_WRITE) < 0) {
      printf("can't open output file: %s\n", outFilePath_.c_str());
      return 0;
    }
  }
  // av_dump_format(fmtCtx, 0, videoName_.c_str(), 1);
  videoStreamIndex = av_find_best_stream(fmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
  //写入文件头信息
  if (avformat_write_header(fmtCtx, nullptr) < 0) {
    printf("Error occurred when opening video output file\n");
    return -1;
  }
  std::cout << "start recoder:" << outFilePath_ << std::endl;
  return 0;
}


int MediaOutput::WritePacket(MediaPacket &packet, bool isVideo, const AVRational &inputTimeBase) {
  if (isVideo) {
    AVStream *videoStream = fmtCtx->streams[videoStreamIndex];
    //convert PTS/DTS
    packet.pkt.pts = av_rescale_q_rnd(packet.pkt.pts, inputTimeBase, videoStream->time_base,
                                      (AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));

    packet.pkt.dts = av_rescale_q_rnd(packet.pkt.dts, inputTimeBase, videoStream->time_base,
                                      (AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));

    packet.pkt.duration = av_rescale_q(packet.pkt.duration, inputTimeBase, videoStream->time_base);

    if (startPts == -1) {
      startPts = packet.pkt.pts;
    }
    packet.pkt.pts = packet.pkt.pts - startPts;
    packet.pkt.dts = packet.pkt.dts - startPts;
    packet.pkt.pos = -1;
    int ret = av_interleaved_write_frame(fmtCtx, &packet.pkt);
    if (ret < 0) {
      perror(ret);
      return -1;
    }
  }
  return 0;
}

int MediaOutput::Close() {
  //写文件尾
  av_write_trailer(fmtCtx);
  std::cout << outFilePath_ << " save success." << std::endl;
  return 0;
}


